/*
 * Copyright (C) 2020 xuexiangjys(xuexiangjys@163.com)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

package com.xuexiang.xui_lib.component.picker;


import ohos.agp.animation.Animator;
import ohos.agp.animation.AnimatorValue;
import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.components.VelocityDetector;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.multimodalinput.event.TouchEvent;

import com.xuexiang.xui_lib.util.AttrValue;
import com.xuexiang.xui_lib.util.TextPaint;
import com.xuexiang.xui_lib.util.TextUtils;

import java.lang.ref.WeakReference;
import java.math.BigDecimal;


/**
 * 刻度尺控件
 *
 * @author XUE
 * @since 2019/4/2 16:33
 */
public class RulerView extends Component implements Component.EstimateSizeListener, Component.DrawTask, Component.TouchEventListener {
    /**
     * 2个大刻度之间间距，默认为1
     */
    private int mScaleLimit = 1;
    /**
     * 尺子高度
     */
    private int mRulerHeight = 150;
    /**
     * 尺子和屏幕顶部以及结果之间的高度
     */
    private int mRulerToResultGap = mRulerHeight / 4;
    /**
     * 刻度平分多少份
     */
    private int mScaleCount = 10;
    /**
     * 刻度间距
     */
    private int mScaleGap = 30;
    /**
     * 刻度最小值
     */
    private int mMinScale = 0;
    /**
     * 第一次显示的刻度
     */
    private float mFirstScale = 50f;
    /**
     * 刻度最大值
     */
    private int mMaxScale = 100;

    /**
     * 背景颜色
     */
    private Color mBgColor;
    /**
     * 小刻度的颜色
     */
    private Color mSmallScaleColor;
    /**
     * 中刻度的颜色
     */
    private Color mMidScaleColor;
    /**
     * 大刻度的颜色
     */
    private Color mLargeScaleColor;
    /**
     * 刻度颜色
     */
    private Color mScaleNumColor;
    /**
     * 结果值颜色
     */
    private Color mResultNumColor;
    /**
     * kg颜色
     */
    private String mUnit = "kg";
    /**
     * kg颜色
     */
    private Color mUnitColor;
    /**
     * 小刻度粗细大小
     */
    private int mSmallScaleStroke = 4;
    /**
     * 中刻度粗细大小
     */
    private int mMidScaleStroke = 8;
    /**
     * 大刻度粗细大小
     */
    private int mLargeScaleStroke = 14;
    /**
     * 结果字体大小
     */
    private int mResultNumTextSize = 55;
    /**
     * 刻度字体大小
     */
    private int mScaleNumTextSize = 35;
    /**
     * 单位字体大小
     */
    private int mUnitTextSize = 25;
    /**
     * 是否显示刻度结果
     */
    private boolean mShowScaleResult = true;
    /**
     * 是否背景显示圆角
     */
    private boolean mIsBgRoundRect = true;
    /**
     * 圆角大小
     */
    private int mRoundRadius = 30;
    /**
     * 结果回调
     */
    private OnChooseResultListener mOnChooseResultListener;
    /**
     * 滑动选择刻度
     */
    private float mComputeScale = -1;
    /**
     * 当前刻度
     */
    public float mCurrentScale = mFirstScale;

    private AnimatorValue mValueAnimator;
    /**
     * 替代VelocityTracker==VelocityDetector；
     */
    private VelocityDetector mVelocityTracker = VelocityDetector.obtainInstance();
    private String mResultText = String.valueOf(mFirstScale);
    private Paint mBgPaint;
    private Paint mSmallScalePaint;
    private Paint mMidScalePaint;
    private Paint mLagScalePaint;
    private TextPaint mScaleNumPaint;
    private TextPaint mResultNumPaint;
    private TextPaint mUnitPaint;
    private Rect mScaleNumRect;
    private Rect mResultNumRect;
    private Rect mKgRect;
    private RectFloat mBgRect;
    private int mHeight, mWidth;
    private int mSmallScaleHeight;
    private int mMidScaleHeight;
    private int mLagScaleHeight;
    private float mDownX;
    private float mMoveX = 0;
    private float mLastMoveX = 0;
    private boolean mIsUp = false;

   /* public RulerView(Context context) {
        this(context, null);
    }*/

    public RulerView(Context context, AttrSet attrs) {
        this(context, attrs, 0);
    }

    public RulerView(Context context, AttrSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context, attrs, defStyleAttr);
        init();
        setEstimateSizeListener(this);
        addDrawTask(this);
        setTouchEventListener(this);
    }

    /**
     * 初始化属性
     *
     * @param context
     * @param attrs
     * @param defStyleAttr
     */
    private void initAttrs(Context context, AttrSet attrs, int defStyleAttr) {
        mScaleLimit = AttrValue.get(attrs, "rv_scaleLimit", mScaleLimit);
        mRulerHeight = AttrValue.getDimension(attrs, "rv_rulerHeight", mRulerHeight);
        mRulerToResultGap = AttrValue.getDimension(attrs, "rv_rulerToResultGap", mRulerToResultGap);
        mScaleCount = AttrValue.get(attrs, "rv_scaleCount", mScaleCount);
        mScaleGap = AttrValue.getDimension(attrs, "rv_scaleGap", mScaleGap);

        mMinScale = AttrValue.get(attrs, "rv_minScale", mMinScale) / mScaleLimit;
        mFirstScale = AttrValue.get(attrs, "rv_firstScale", mFirstScale) / mScaleLimit;

        mMaxScale = AttrValue.get(attrs, "rv_maxScale", mMaxScale) / mScaleLimit;

        mBgColor = AttrValue.get(attrs, "rv_bgColor", new Color(Color.getIntColor("#FFFCFFFC")));
        mSmallScaleColor = AttrValue.get(attrs, "rv_smallScaleColor", new Color(Color.getIntColor("#FF999999")));

        mMidScaleColor = AttrValue.get(attrs, "rv_midScaleColor", new Color(Color.getIntColor("#FF666666")));
        mLargeScaleColor = AttrValue.get(attrs, "rv_largeScaleColor", new Color(Color.getIntColor("#FF50B586")));
        mScaleNumColor = AttrValue.get(attrs, "rv_scaleNumColor", new Color(Color.getIntColor("#FF333333")));
        mResultNumColor = AttrValue.get(attrs, "rv_resultNumColor", new Color(Color.getIntColor("#FF50B586")));
        mUnitColor = AttrValue.get(attrs, "rv_unitColor", new Color(Color.getIntColor("#FF50B586")));

        String tempUnit = mUnit;
        mUnit = AttrValue.get(attrs, "rv_unit", "");
        if (TextUtils.isEmpty(mUnit)) {
            mUnit = tempUnit;
        }
        mSmallScaleStroke = AttrValue.getDimension(attrs, "rv_smallScaleStroke", mSmallScaleStroke);
        mMidScaleStroke = AttrValue.getDimension(attrs, "rv_midScaleStroke", mMidScaleStroke);
        mLargeScaleStroke = AttrValue.getDimension(attrs, "rv_largeScaleStroke", mLargeScaleStroke);
        mResultNumTextSize = AttrValue.getDimension(attrs, "rv_resultNumTextSize", mResultNumTextSize);
        mScaleNumTextSize = AttrValue.getDimension(attrs, "rv_scaleNumTextSize", mScaleNumTextSize);
        mUnitTextSize = AttrValue.getDimension(attrs, "rv_unitTextSize", mUnitTextSize);
        mShowScaleResult = AttrValue.get(attrs, "rv_showScaleResult", mShowScaleResult);
        mIsBgRoundRect = AttrValue.get(attrs, "rv_isBgRoundRect", mIsBgRoundRect);
        mRoundRadius = AttrValue.getDimension(attrs, "rv_roundRadius", mRoundRadius);
    }


    private void init() {
        mBgPaint = new Paint();
        mSmallScalePaint = new Paint();
        mMidScalePaint = new Paint();
        mLagScalePaint = new Paint();
        mScaleNumPaint = new TextPaint();
        mResultNumPaint = new TextPaint();
        mUnitPaint = new TextPaint();

        mBgPaint.setColor(mBgColor);
        mSmallScalePaint.setColor(mSmallScaleColor);
        mMidScalePaint.setColor(mMidScaleColor);
        mLagScalePaint.setColor(mLargeScaleColor);
        mScaleNumPaint.setColor(mScaleNumColor);
        mResultNumPaint.setColor(mResultNumColor);
        mUnitPaint.setColor(mUnitColor);

        mResultNumPaint.setStyle(Paint.Style.FILL_STYLE);
        mUnitPaint.setStyle(Paint.Style.FILL_STYLE);
        mBgPaint.setStyle(Paint.Style.FILL_STYLE);
        mSmallScalePaint.setStyle(Paint.Style.FILL_STYLE);
        mMidScalePaint.setStyle(Paint.Style.FILL_STYLE);
        mLagScalePaint.setStyle(Paint.Style.FILL_STYLE);

        mLagScalePaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
        mMidScalePaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);
        mSmallScalePaint.setStrokeCap(Paint.StrokeCap.ROUND_CAP);

        mSmallScalePaint.setStrokeWidth(mSmallScaleStroke);
        mMidScalePaint.setStrokeWidth(mMidScaleStroke);
        mLagScalePaint.setStrokeWidth(mLargeScaleStroke);

        mResultNumPaint.setTextSize(mResultNumTextSize);
        mUnitPaint.setTextSize(mUnitTextSize);
        mScaleNumPaint.setTextSize(mScaleNumTextSize);

        mBgRect = new RectFloat();
        mResultNumRect = new Rect();
        mScaleNumRect = new Rect();
        mKgRect = new Rect();

        mResultNumRect = mResultNumPaint.getTextBounds(mResultText);
        mKgRect = mUnitPaint.getTextBounds(mResultText);

        mSmallScaleHeight = mRulerHeight / 4;
        mMidScaleHeight = mRulerHeight / 2;
        mLagScaleHeight = mRulerHeight / 2 + 5;
        mValueAnimator = new AnimatorValue();

    }


    @Override
    public boolean onEstimateSize(int widthMeasureSpec, int heightMeasureSpec) {
        int heightModule = EstimateSpec.getMode(heightMeasureSpec);
        int heightSize = EstimateSpec.getSize(heightMeasureSpec);
        int widthSize = EstimateSpec.getSize(widthMeasureSpec);

        switch (heightModule) {
            case EstimateSpec.UNCONSTRAINT:
                mHeight = mRulerHeight + (mShowScaleResult ? mResultNumRect.getHeight() : 0) + mRulerToResultGap * 2 + getPaddingTop() + getPaddingBottom();
                break;
            case EstimateSpec.PRECISE:
            case EstimateSpec.NOT_EXCEED:
                mHeight = heightSize + getPaddingTop() + getPaddingBottom();
                break;
            default:
                break;
        }

        mWidth = widthSize + getPaddingLeft() + getPaddingRight();

        setEstimatedSize(mWidth, mHeight);
        return false;
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        drawBg(canvas);
        drawScaleAndNum(canvas);
        drawResultText(canvas, mResultText);
    }

    @Override
    public boolean onTouchEvent(Component component, TouchEvent touchEvent) {
        if (getComponentParent() != null) {
            //拦截事件，不让父布局获取
            //  getParent().requestDisallowInterceptTouchEvent(true);
        }
        final int actionIndex = touchEvent.getIndex();
        float currentX = touchEvent.getPointerPosition(actionIndex).getX();
        mIsUp = false;
        mVelocityTracker.calculateCurrentVelocity(500);
        mVelocityTracker.addEvent(touchEvent);
        switch (touchEvent.getAction()) {
            case TouchEvent.PRIMARY_POINT_DOWN:
                //按下时如果属性动画还没执行完,就终止,记录下当前按下点的位置
                if (mValueAnimator != null && mValueAnimator.isRunning()) {
                    mValueAnimator.end();
                    mValueAnimator.cancel();
                }
                mDownX = touchEvent.getPointerPosition(actionIndex).getX();
                break;
            case TouchEvent.POINT_MOVE:
                //滑动时候,通过假设的滑动距离,做超出左边界以及右边界的限制。
                mMoveX = currentX - mDownX + mLastMoveX;
                if (mMoveX >= mWidth / 2F) {
                    mMoveX = mWidth / 2F;
                } else if (mMoveX <= getWhichScaleMoveX(mMaxScale)) {
                    mMoveX = getWhichScaleMoveX(mMaxScale);
                }
                break;
            case TouchEvent.PRIMARY_POINT_UP:
                //手指抬起时候制造惯性滑动
                mLastMoveX = mMoveX;
                float veLocity[] = mVelocityTracker.getVelocity();
                int xVelocity = (int) veLocity[0];
                autoVelocityScroll(xVelocity);
                mVelocityTracker.clear();
                break;
            default:
                break;
        }
        invalidate();
        return true;
    }

    /**
     * get the animated value with fraction and values
     *
     * @param fraction 0~1
     * @param values float array
     * @return float animated value
     */
    public static float getAnimatedValue(float fraction, float... values) {
        if (values == null || values.length == 0) {
            return 0;
        }
        if (values.length == 1) {
            return values[0] * fraction;
        } else {
            if (fraction == 1) {
                return values[values.length - 1];
            }
            float oneFraction = 1f / (values.length - 1);
            float offFraction = 0;
            for (int i = 0; i < values.length - 1; i++) {
                if (offFraction + oneFraction >= fraction) {
                    return values[i] + (fraction - offFraction) * (values.length - 1) * (values[i + 1] - values[i]);
                }
                offFraction += oneFraction;
            }
        }
        return 0;
    }

    private void autoVelocityScroll(int xVelocity) {
        //惯性滑动的代码,速率和滑动距离,以及滑动时间需要控制的很好,应该网上已经有关于这方面的算法了吧。。这里是经过N次测试调节出来的惯性滑动
        if (Math.abs(xVelocity) < 50) {
            mIsUp = true;
            return;
        }
        if (mValueAnimator.isRunning()) {
            return;
        }

        mValueAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
            @Override
            public void onUpdate(AnimatorValue animatorValue, float v) {
                mMoveX += (int) getAnimatedValue(v, 0, xVelocity / 20f);
                if (mMoveX >= mWidth / 2F) {
                    mMoveX = mWidth / 2F;
                } else if (mMoveX <= getWhichScaleMoveX(mMaxScale)) {
                    mMoveX = getWhichScaleMoveX(mMaxScale);
                }
                mLastMoveX = mMoveX;
                invalidate();
            }
        });
        mValueAnimator.setStateChangedListener(new Animator.StateChangedListener() {
            @Override
            public void onStart(Animator animator) {

            }

            @Override
            public void onStop(Animator animator) {

            }

            @Override
            public void onCancel(Animator animator) {

            }

            @Override
            public void onEnd(Animator animator) {
                mIsUp = true;
                invalidate();
            }

            @Override
            public void onPause(Animator animator) {

            }

            @Override
            public void onResume(Animator animator) {

            }
        });

        mValueAnimator.start();
    }

    private float getWhichScaleMoveX(float scale) {
        return mWidth / 2F - mScaleGap * mScaleCount * (scale - mMinScale);
    }

    private void drawScaleAndNum(Canvas canvas) {
        canvas.translate(0, (mShowScaleResult ? mResultNumRect.getHeight() : 0) + mRulerToResultGap);//移动画布到结果值的下面

        int num1;//确定刻度位置
        float num2;

        if (mFirstScale != -1) {   //第一次进来的时候计算出默认刻度对应的假设滑动的距离moveX
            mMoveX = getWhichScaleMoveX(mFirstScale);          //如果设置了默认滑动位置，计算出需要滑动的距离
            mLastMoveX = mMoveX;
            mFirstScale = -1;                                //将结果置为-1，下次不再计算初始位置
        }

        if (mComputeScale != -1) {//弹性滑动到目标刻度
            mLastMoveX = mMoveX;
            if (mValueAnimator != null && !mValueAnimator.isRunning()) {
                mValueAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
                    @Override
                    public void onUpdate(AnimatorValue animatorValue, float v) {
                        mMoveX = getAnimatedValue(v, getWhichScaleMoveX(mCurrentScale), getWhichScaleMoveX(mComputeScale));
                        mLastMoveX = mMoveX;
                        invalidate();
                    }
                });

                mValueAnimator.setStateChangedListener(new Animator.StateChangedListener() {
                    @Override
                    public void onStart(Animator animator) {

                    }

                    @Override
                    public void onStop(Animator animator) {

                    }

                    @Override
                    public void onCancel(Animator animator) {

                    }

                    @Override
                    public void onEnd(Animator animator) {
                        //这里是滑动结束时候回调给使用者的结果值
                        mComputeScale = -1;
                    }

                    @Override
                    public void onPause(Animator animator) {

                    }

                    @Override
                    public void onResume(Animator animator) {

                    }
                });
                mValueAnimator.setDuration(Math.abs((long) ((getWhichScaleMoveX(mComputeScale) - getWhichScaleMoveX(mCurrentScale)) / 100)));
                mValueAnimator.start();
            }
        }

        num1 = -(int) (mMoveX / mScaleGap);                   //滑动刻度的整数部分
        num2 = (mMoveX % mScaleGap);                         //滑动刻度的小数部分
        canvas.save();                                      //保存当前画布

        int rulerRight = 0;                                    //准备开始绘制当前屏幕,从最左面开始

        if (mIsUp) {   //这部分代码主要是计算手指抬起时，惯性滑动结束时，刻度需要停留的位置
            num2 = ((mMoveX - mWidth / 2F % mScaleGap) % mScaleGap);     //计算滑动位置距离整点刻度的小数部分距离
            if (num2 <= 0) {
                num2 = mScaleGap - Math.abs(num2);
            }
            int leftScroll = (int) Math.abs(num2);                        //当前滑动位置距离左边整点刻度的距离
            int rightScroll = (int) (mScaleGap - Math.abs(num2));         //当前滑动位置距离右边整点刻度的距离

            float moveX2 = num2 <= mScaleGap / 2F ? mMoveX - leftScroll : mMoveX + rightScroll; //最终计算出当前位置到整点刻度位置需要滑动的距离

            if (mValueAnimator != null && !mValueAnimator.isRunning()) {
                //手指抬起，并且当前没有惯性滑动在进行，创建一个惯性滑动
                mValueAnimator.setValueUpdateListener(new AnimatorValue.ValueUpdateListener() {
                    @Override
                    public void onUpdate(AnimatorValue animatorValue, float v) {
                        mMoveX = getAnimatedValue(v, mMoveX, moveX2);
                        mLastMoveX = mMoveX;//不断滑动去更新新的位置
                        invalidate();
                    }
                });

                mValueAnimator.setStateChangedListener(new Animator.StateChangedListener() {
                    @Override
                    public void onStart(Animator animator) {

                    }

                    @Override
                    public void onStop(Animator animator) {

                    }

                    @Override
                    public void onCancel(Animator animator) {

                    }

                    @Override
                    public void onEnd(Animator animator) {
                        //这里是滑动结束时候回调给使用者的结果值
                        if (mOnChooseResultListener != null) {
                            mOnChooseResultListener.onEndResult(mResultText);
                        }
                    }

                    @Override
                    public void onPause(Animator animator) {

                    }

                    @Override
                    public void onResume(Animator animator) {

                    }
                });
                mValueAnimator.setDuration(300);
                mValueAnimator.start();
                mIsUp = false;
            }
            //重新计算当前滑动位置的整数以及小数位置
            num1 = (int) -(mMoveX / mScaleGap);
            num2 = (mMoveX % mScaleGap);
        }

        //不加该偏移的话，滑动时刻度不会落在0~1之间只会落在整数上面,其实这个都能设置一种模式了，毕竟初衷就是指针不会落在小数上面
        canvas.translate(num2, 0);

        //这里是滑动时候不断回调给使用者的结果值
        mCurrentScale = new WeakReference<>(new BigDecimal(((mWidth / 2F - mMoveX) / (mScaleGap * mScaleCount) + mMinScale) * mScaleLimit)).get().setScale(1, BigDecimal.ROUND_HALF_UP).floatValue();

        mResultText = String.valueOf(mCurrentScale);


        if (mOnChooseResultListener != null) {
            mOnChooseResultListener.onScrollResult(mResultText); //接口不断回调给使用者结果值
        }
        //绘制当前屏幕可见刻度,不需要裁剪屏幕,while循环只会执行·屏幕宽度/刻度宽度·次,大部分的绘制都是if(curDis<mWidth)这样子内存暂用相对来说会比较高。。
        while (rulerRight < mWidth) {
            if (num1 % mScaleCount == 0) {    //绘制整点刻度以及文字
                if ((mMoveX >= 0 && rulerRight < mMoveX - mScaleGap) || mWidth / 2F - rulerRight <= getWhichScaleMoveX(mMaxScale + 1) - mMoveX) {
                    //当滑动出范围的话，不绘制，去除左右边界
                } else {
                    //绘制刻度，绘制刻度数字
                    canvas.drawLine(0, 0, 0, mMidScaleHeight, mMidScalePaint);
                    mScaleNumRect = mScaleNumPaint.getTextBounds(num1 / mScaleGap + mMinScale + "");

                    canvas.drawText(mScaleNumPaint, (num1 / mScaleCount + mMinScale) * mScaleLimit + "", -mScaleNumRect.getWidth() / 2F, mLagScaleHeight +
                        (mRulerHeight - mLagScaleHeight) / 2F + mScaleNumRect.getHeight());

                }

            } else {   //绘制小数刻度
                if ((mMoveX >= 0 && rulerRight < mMoveX) || mWidth / 2F - rulerRight < getWhichScaleMoveX(mMaxScale) - mMoveX) {
                    //当滑动出范围的话，不绘制，去除左右边界
                } else {
                    //绘制小数刻度
                    canvas.drawLine(0, 0, 0, mSmallScaleHeight, mSmallScalePaint);
                }
            }
            ++num1;  //刻度加1
            rulerRight += mScaleGap;  //绘制屏幕的距离在原有基础上+1个刻度间距
            canvas.translate(mScaleGap, 0); //移动画布到下一个刻度
        }

        canvas.restore();
        //绘制屏幕中间用来选中刻度的最大刻度
        canvas.drawLine(mWidth / 2F, 0, mWidth / 2F, mLagScaleHeight, mLagScalePaint);

    }

    //绘制上面的结果 结果值+单位
    private void drawResultText(Canvas canvas, String resultText) {
        if (!mShowScaleResult) {   //判断用户是否设置需要显示当前刻度值，如果否则取消绘制
            return;
        }
        canvas.translate(0, -mResultNumRect.getHeight() - mRulerToResultGap / 2F);  //移动画布到正确的位置来绘制结果值
        mResultNumRect = mResultNumPaint.getTextBounds(resultText);
        //绘制当前刻度结果值
        canvas.drawText(mResultNumPaint, resultText, mWidth / 2F - mResultNumRect.getWidth() / 2F, mResultNumRect.getHeight());
        int resultNumRight = mWidth / 2 + mResultNumRect.getWidth() / 2 + 10;
        canvas.drawText(mUnitPaint, mUnit, resultNumRight, mKgRect.getHeight() + 2);            //在当前刻度结果值的又面10px的位置绘制单位
    }

    private void drawBg(Canvas canvas) {
        mBgRect.fuse(0, 0, mWidth, mHeight);
        if (mIsBgRoundRect) {
            //椭圆的用于圆形角x-radius
            canvas.drawRoundRect(mBgRect, mRoundRadius, mRoundRadius, mBgPaint);
        } else {
            canvas.drawRect(mBgRect, mBgPaint);
        }
    }

    private void computeScrollTo(float scale) {
        scale = scale / mScaleLimit;
        if (scale < mMinScale || scale > mMaxScale) {
            return;
        }
        mComputeScale = scale;
        invalidate();
    }

    /**
     * 选择结果监听
     */
    public interface OnChooseResultListener {
        /**
         * 滑动选择结束
         *
         * @param result
         */
        void onEndResult(String result);

        /**
         * 开始滑动选择
         *
         * @param result
         */
        void onScrollResult(String result);
    }

    public void setRulerHeight(int rulerHeight) {
        this.mRulerHeight = rulerHeight;
        invalidate();
    }

    public void setRulerToResultGap(int rulerToResultGap) {
        this.mRulerToResultGap = rulerToResultGap;
        invalidate();
    }

    public void setScaleCount(int scaleCount) {
        this.mScaleCount = scaleCount;
        invalidate();
    }

    public void setScaleGap(int scaleGap) {
        this.mScaleGap = scaleGap;
        invalidate();
    }

    public void setMinScale(int minScale) {
        this.mMinScale = minScale;
        invalidate();
    }

    public void setFirstScale(float firstScale) {
        this.mFirstScale = firstScale;
        invalidate();
    }

    public void setMaxScale(int maxScale) {
        this.mMaxScale = maxScale;
        invalidate();
    }

    public void setBgColor(Color bgColor) {
        this.mBgColor = bgColor;
        invalidate();
    }

    public void setSmallScaleColor(Color smallScaleColor) {
        this.mSmallScaleColor = smallScaleColor;
        invalidate();
    }

    public void setMidScaleColor(Color midScaleColor) {
        this.mMidScaleColor = midScaleColor;
        invalidate();
    }

    public void setLargeScaleColor(Color largeScaleColor) {
        this.mLargeScaleColor = largeScaleColor;
    }

    public void setScaleNumColor(Color scaleNumColor) {
        this.mScaleNumColor = scaleNumColor;
        invalidate();
    }

    public void setResultNumColor(Color resultNumColor) {
        this.mResultNumColor = resultNumColor;
        invalidate();
    }

    public void setUnit(String unit) {
        this.mUnit = unit;
        invalidate();
    }

    public void setUnitColor(Color unitColor) {
        this.mUnitColor = unitColor;
        invalidate();
    }

    public void setSmallScaleStroke(int smallScaleStroke) {
        this.mSmallScaleStroke = smallScaleStroke;
        invalidate();
    }

    public void setMidScaleStroke(int midScaleStroke) {
        this.mMidScaleStroke = midScaleStroke;
        invalidate();
    }

    public void setLargeScaleStroke(int largeScaleStroke) {
        this.mLargeScaleStroke = largeScaleStroke;
        invalidate();
    }

    public void setResultNumTextSize(int resultNumTextSize) {
        this.mResultNumTextSize = resultNumTextSize;
        invalidate();
    }

    public void setScaleNumTextSize(int scaleNumTextSize) {
        this.mScaleNumTextSize = scaleNumTextSize;
        invalidate();
    }

    public void setUnitTextSize(int unitTextSize) {
        this.mUnitTextSize = unitTextSize;
        invalidate();
    }

    public void setShowScaleResult(boolean showScaleResult) {
        this.mShowScaleResult = showScaleResult;
        invalidate();
    }

    public void setIsBgRoundRect(boolean bgRoundRect) {
        mIsBgRoundRect = bgRoundRect;
        invalidate();
    }

    public void setScaleLimit(int scaleLimit) {
        this.mScaleLimit = scaleLimit;
        invalidate();
    }

    /**
     * 设置刻度尺的值
     *
     * @param value
     */
    public void setCurrentValue(float value) {
        computeScrollTo(value);
    }

    /**
     * 获取当前刻度尺的刻度
     *
     * @return float
     */
    public float getCurrentValue() {
        return mCurrentScale;
    }

    /**
     * 获取选择值
     *
     * @return String
     */
    public String getSelectValue() {
        return mResultText;
    }

    /**
     * 设置选择监听
     *
     * @param onChooseResultListener
     * @return RulerView
     */
    public RulerView setOnChooseResultListener(OnChooseResultListener onChooseResultListener) {
        this.mOnChooseResultListener = onChooseResultListener;
        return this;
    }
}
